package com.sojson.annotation.aspect;

import java.io.IOException;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import com.sojson.annotation.ReCommit;
import com.sojson.config.exception.TransException;
import com.sojson.constant.Constant;
import com.sojson.entity.po.Member;
import com.sojson.enums.core.ELoginMoreOnlineType;
import com.sojson.util.annotation.AnnoUtil;
import com.sojson.util.cache.CacheUtil;
import com.sojson.util.lock.CustomLock;
import com.sojson.util.lock.LockUtil;
import com.sojson.util.servlet.ServletUtil;
import com.sojson.util.token.Token;
import com.sojson.util.token.TokenUtil;

/**
 * 防止重复提交切面
 * 
 * @author liu
 * @date 2021-08-16
 */
@Aspect
@Component
public class ReCommitAspect extends PointcutsWebBase {

    /** 存储和删除的Key前缀 */
    private static final String KEY_PREFIX = "ReCommit";
    /** 默认错误信息 */
    private static final String MSG = "操作繁忙,请重试";

    /**
     * 请求处理之前和之后
     * 
     * @param pjp 切点
     * @return 接口返回的内容,可以拦截(这里如果不返回就等于接口不返回)
     * @throws Throwable
     */
    @Around(POINTCUT_RE_COMMIT)
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        // 错误信息
        String msg = MSG;
        // 超时时间
        int expireTime = Constant.RE_COMMIT_EXPIRE_TIME_DEFAULT;
        // 获取注解
        ReCommit reCommit = AnnoUtil.getAnnoByMethodAndClass(pjp, ReCommit.class);
        if (reCommit != null) {
            expireTime = reCommit.expireTime();
            if (reCommit.msg() != null) {
                msg = reCommit.msg();
            }
        }
        // 获取存储和删除的Key
        String key = getKey(ServletUtil.getRequestMapping());

        // 获取锁
        CustomLock lock = LockUtil.getLockRedis(KEY_PREFIX + key);
        // 上锁
        lock.defaultLock();
        // 判断Key是否存在
        boolean exists = CacheUtil.exists(key);
        // 如果存在就结束
        if (exists) {
            // 释放锁
            lock.unlock();
            // 返回错误信息
            throw new TransException(msg);
        }
        // 创建Key
        CacheUtil.setexYes(key, 1, expireTime / 1000);
        // 释放锁
        lock.unlock();

        // 调用接口
        Object proceed = pjp.proceed();

        // 删除Key
        CacheUtil.delByKey(key);
        // 继续执行下一个切面
        return proceed;
    }

    /**
     * 获取存储和删除的Key
     * 
     * @param key
     * @return
     * @throws IOException 
     */
    private String getKey(String key) throws IOException {
        String userNo = null;

        // 如果登录了就用用户编号作为唯一标识,没有登录就用TokenId作为唯一标识
        Token token = TokenUtil.getToken();
        if (TokenUtil.isLogin(token)) {
            Member member = token.getMember();
            Integer typeMoreOnline = member.getTypeMoreOnline();
            if (typeMoreOnline == ELoginMoreOnlineType.ONE.getCode()) {
                userNo = member.getNo();
            } else if (typeMoreOnline == ELoginMoreOnlineType.MACHINE_ONE.getCode()) {
                userNo = member.getNo() + "_" + token.getKeyLoginDevice();
            } else if (typeMoreOnline == ELoginMoreOnlineType.NO.getCode()) {
                userNo = token.getId();
            } else if (member.getOnlineMaxNumber().intValue() < 2) {
                if (typeMoreOnline == ELoginMoreOnlineType.NUMBER.getCode()) {
                    userNo = member.getNo();
                } else if (typeMoreOnline == ELoginMoreOnlineType.MACHINE_NUMBER.getCode()) {
                    userNo = member.getNo() + "_" + token.getKeyLoginDevice();
                }
            } else if (typeMoreOnline == ELoginMoreOnlineType.NUMBER.getCode()
                || typeMoreOnline == ELoginMoreOnlineType.MACHINE_NUMBER.getCode()) {
                userNo = token.getId();
            }
        } else {
            userNo = TokenUtil.getClaims(true).getId();
        }

        return KEY_PREFIX + "_" + key + "_" + userNo;
    }

}